home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / pc / SATAN11.ZIP / SRC / FPING / FPING.C < prev    next >
Encoding:
C/C++ Source or Header  |  1995-04-03  |  23.5 KB  |  830 lines

  1. /* 
  2.  * fping: fast-ping, file-ping
  3.  *
  4.  * Used to send out ping requests to a list of hosts in a round robin
  5.  * fashion. 
  6.  *
  7.  *
  8.  *   fping has been compiled tested under the following systems:
  9.  *
  10.  *  Ultrix 4.2a DECstation
  11.  *  Ultrix 3.1 VAX
  12.  *  NeXT 2.1
  13.  *  SunOS 4.1.1 Sparcstation (gcc and cc)
  14.  *  AIX 3.1 RISC System/6000
  15.  *
  16.  */
  17.  
  18. /* 
  19.  ***************************************************
  20.  *
  21.  * Standard RCS Header information (see co(1))
  22.  *
  23.  * $Author: schemers $
  24.  *
  25.  * $Date: 1993/02/23 00:16:38 $
  26.  *
  27.  * $Revision: 1.20 $
  28.  *
  29.  * $Locker: schemers $
  30.  *
  31.  * $Source: /networking/src/fping/RCS/fping.c,v $
  32.  *
  33.  * $State: Exp $
  34.  *
  35.  * $Log: fping.c,v $
  36.  * Revision 1.20  1993/02/23  00:16:38  schemers
  37.  * fixed syntax error (should have compiled before checking in...)
  38.  *
  39.  * Revision 1.19  1993/02/23  00:15:15  schemers
  40.  * turned off printing of "is alive" when -a is specified.
  41.  *
  42.  * Revision 1.18  1992/07/28  15:16:44  schemers
  43.  * added a fflush(stdout) call before the summary is sent to stderr, so
  44.  * everything shows up in the right order.
  45.  *
  46.  * Revision 1.17  1992/07/23  03:29:42  schemers
  47.  * fixed declaration of timeval_diff.
  48.  *
  49.  * Revision 1.16  1992/07/22  19:24:37  schemers
  50.  * Modified file reading so it would skip blanks lines or lines starting
  51.  * with a '#'. Now you can do something like:
  52.  *
  53.  * fping -ad < /etc/hosts
  54.  *
  55.  * Revision 1.15  1992/07/21  17:07:18  schemers
  56.  * Put in sanity checks so only root can specify "dangerous" options.
  57.  * Changed usage to show switchs in alphabetical order.
  58.  *
  59.  * Revision 1.14  1992/07/21  16:40:52  schemers
  60.  * Now when sendto returns an error, the host is considered unreachable and
  61.  * and the error message (from errno) is displayed.
  62.  *
  63.  * Revision 1.13  1992/07/17  21:02:17  schemers
  64.  * changed default timeout to 2500 msec (for WANs), and default try
  65.  * to 3. This gives 10 second overall timeout.
  66.  *
  67.  * Added -e option for showing elapsed (round-trip) time on packets
  68.  *
  69.  * Modified -s option to inlude to round-trip stats
  70.  *
  71.  * Added #ifndef DEFAULT_* stuff its easier to change the defaults
  72.  *
  73.  * Reorganized main loop.
  74.  *
  75.  * cleaned up timeval stuff. removed set_timeval and timeval_expired
  76.  * since they aren't needed anymore. Just use timeval_diff.
  77.  *
  78.  * Revision 1.12  1992/07/17  16:38:54  schemers
  79.  * move socket create call so I could do a setuid(getuid()) before the
  80.  * fopen call is made. Once the socket is created root privs aren't needed
  81.  * to send stuff out on it.
  82.  *
  83.  * Revision 1.11  1992/07/17  16:28:38  schemers
  84.  * moved num_timeout counter. It really was for debug purposes and didn't
  85.  * make sense to the general public :-) Now it is the number of timeouts
  86.  * (pings that didn't get received with the time limit).
  87.  *
  88.  * Revision 1.10  1992/07/16  16:24:38  schemers
  89.  * changed usage() to use fprintf(stderr,"...");
  90.  *
  91.  * Revision 1.9  1992/07/16  16:00:04  schemers
  92.  * Added _NO_PROTO stuff for older compilers, and _POSIX_SOURCE
  93.  * for unistd.h, and _POSIX_SOURCE for stdlib.h. Also added
  94.  * check for __cplusplus.
  95.  *
  96.  * Revision 1.8  1992/07/16  05:44:41  schemers
  97.  * changed -a and -u to only show hostname in results. This is
  98.  * for easier parsing. Also added -v flag
  99.  *
  100.  * Revision 1.7  1992/07/14  18:45:23  schemers
  101.  * initialized last_time in add_host function
  102.  *
  103.  * Revision 1.6  1992/07/14  18:32:40  schemers
  104.  * changed select to use FD_ macros
  105.  *
  106.  * Revision 1.5  1992/07/14  17:21:22  schemers
  107.  * standardized exit status codes
  108.  *
  109.  * Revision 1.4  1992/06/26  15:25:35  schemers
  110.  * changed name from rrping to fping
  111.  *
  112.  * Revision 1.3  1992/06/24  15:39:32  schemers
  113.  * added -d option for unreachable systems
  114.  *
  115.  * Revision 1.2  1992/06/23  03:01:23  schemers
  116.  * misc fixes from R.L. "Bob" Morgan
  117.  *
  118.  * Revision 1.1  1992/06/19  18:23:52  schemers
  119.  * Initial revision
  120.  *
  121.  *--------------------------------------------------
  122.  * Copyright (c) 1992 Board of Trustees
  123.  *            Leland Stanford Jr. University
  124.  ***************************************************
  125.  */
  126.  
  127. /*
  128.  * Redistribution and use in source and binary forms are permitted
  129.  * provided that the above copyright notice and this paragraph are
  130.  * duplicated in all such forms and that any documentation,
  131.  * advertising materials, and other materials related to such
  132.  * distribution and use acknowledge that the software was developed
  133.  * by Stanford University.  The name of the University may not be used 
  134.  * to endorse or promote products derived from this software without 
  135.  * specific prior written permission.
  136.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  137.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  138.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  139.  */
  140.  
  141. #ifndef _NO_PROTO
  142. #if !__STDC__ && !defined(__cplusplus) && !defined(FUNCPROTO) \
  143.                                                  && !defined(_POSIX_SOURCE)
  144. #define _NO_PROTO
  145. #endif /* __STDC__ */
  146. #endif /* _NO_PROTO */
  147.  
  148. #ifdef __cplusplus
  149. extern "C" {
  150. #endif
  151.  
  152. #include <stdio.h>
  153. #include <errno.h>
  154. #include <time.h>
  155.  
  156. #ifdef _POSIX_SOURCE
  157. #include <unistd.h>
  158. #endif
  159.  
  160. #ifdef __STDC__
  161. #include <stdlib.h>
  162. #endif
  163.  
  164. #include <string.h>
  165.  
  166. #include <sys/types.h>
  167. #include <sys/time.h>
  168. #include <sys/socket.h>
  169.  
  170.  
  171. #include <netinet/in_systm.h>
  172. #include <netinet/in.h>
  173. #include <netinet/ip.h>
  174. #include <netinet/ip_icmp.h>
  175. #include <arpa/inet.h>
  176.  
  177. #include <netdb.h>
  178.  
  179. /* RS6000 has sys/select.h */
  180. #ifndef FD_SET
  181. #include <sys/select.h>
  182. #endif
  183.  
  184. /* externals */
  185.  
  186. extern char *optarg;
  187. extern int optind,opterr;
  188. #ifndef SYS_ERRLIST_DECLARED
  189. extern char *sys_errlist[];
  190. #endif
  191.  
  192. #ifdef __cplusplus
  193. }
  194. #endif
  195.  
  196. /* constants */
  197.  
  198. #ifndef DEFAULT_INTERVAL
  199. #define DEFAULT_INTERVAL 25        /* default time between packets (msec) */
  200. #endif
  201.  
  202. #ifndef DEFAULT_TIMEOUT
  203. #define DEFAULT_TIMEOUT 2500       /* individual host timeouts */
  204. #endif
  205.  
  206. #ifndef DEFAULT_RETRY 
  207. #define DEFAULT_RETRY 3            /* number of times to retry a host */
  208. #endif
  209.  
  210.  
  211. /* typedef's */
  212.  
  213. /* entry used to keep track of each host we are pinging */
  214.  
  215. typedef struct host_entry {
  216.      char                 *host;              /* text description of host */
  217.      struct sockaddr_in   saddr;              /* internet address */
  218.      int                  i;                  /* index into array */
  219.      int                  num_packets_sent;   /* number of ping packets sent */
  220.      struct host_entry    *prev,*next;        /* doubly linked list */
  221.      struct timeval       last_time;          /* time of last packet sent */
  222. } HOST_ENTRY;
  223.  
  224. /* globals */
  225.  
  226. HOST_ENTRY *rrlist=NULL;    /* linked list of hosts be pinged */
  227. HOST_ENTRY **table=NULL;    /* array of pointers to items in the list */
  228. HOST_ENTRY *cursor;
  229.  
  230. char *prog;
  231. int ident;                  /* our pid */
  232. int s;                      /* socket */
  233.  
  234. int retry = DEFAULT_RETRY;
  235. int timeout = DEFAULT_TIMEOUT;
  236. int interval = DEFAULT_INTERVAL;
  237.  
  238. long max_reply=0;
  239. long min_reply=10000;
  240. int total_replies=0;
  241. double sum_replies=0;
  242.  
  243. struct timeval timeout_timeval;
  244. struct timezone tz;
  245.  
  246. int num_waiting=0;                 /* number of hosts we are pinging */
  247. int num_hosts;                     /* total number of hosts */
  248.  
  249. int num_alive=0,                  /* total number alive */
  250.     num_unreachable=0,            /* total number unreachable */
  251.     num_noaddress=0;              /* total number of addresses not found */
  252.  
  253. int num_timeout=0,                /* number of times select timed out */
  254.     num_pingsent=0,               /* total pings sent */
  255.     num_pingreceived=0;           /* total pings received */
  256.  
  257. struct timeval current_time;      /* current time (pseudo) */
  258. struct timeval start_time; 
  259. struct timeval end_time;   
  260.  
  261. /* switches */
  262. int verbose_flag,dns_flag,stats_flag,unreachable_flag,alive_flag;
  263. int elapsed_flag,version_flag;
  264.  
  265. char *filename=NULL;               /* file containing hosts to ping */
  266.  
  267. /* forward declarations */
  268.  
  269. #ifdef _NO_PROTO
  270.  
  271. void add_host();
  272. void crash_and_burn();
  273. void errno_crash_and_burn();
  274. char *get_host_by_address();
  275. int in_cksum();
  276. int recvfrom_wto ();
  277. void remove_job();
  278. void send_ping();
  279. void usage();
  280. int wait_for_reply();
  281. long timeval_diff();
  282. #else
  283.  
  284. void add_host(char *host);
  285. void crash_and_burn(char *message);
  286. void errno_crash_and_burn(char *message);
  287. char *get_host_by_address(struct in_addr in);
  288. int in_cksum(u_short *p, int n);
  289. int recvfrom_wto (int s, char *buf, int len, struct sockaddr *saddr, int timo);
  290. void remove_job(HOST_ENTRY *h);
  291. void send_ping(int s,HOST_ENTRY *h);
  292. long timeval_diff(struct timeval *a,struct timeval *b);
  293. void usage();
  294. int wait_for_reply();
  295.  
  296. #endif
  297.  
  298. #define bcopy(s,d,l)    memcpy(d,s,l)
  299. #define bzero(d,l)    memset(d,0,l)
  300.  
  301. #ifdef _NO_PROTO
  302. int main(argc,argv)
  303. int argc; char **argv;
  304. #else
  305. int main(int argc, char **argv)
  306. #endif
  307. {
  308.  
  309.   int c;
  310.  
  311.   struct protoent *proto;
  312.  
  313.   /* check if we are root */
  314.  
  315.   if (geteuid()) {
  316.       fprintf(stderr,
  317.         "This program can only be run by root, or it must be setuid root.\n");
  318.       exit(3);
  319.   }
  320.  
  321.   if ((proto = getprotobyname("icmp")) == NULL) 
  322.              crash_and_burn("icmp: unknown protocol");
  323.  
  324.   /* create the socket here as root. Then setuid back to 
  325.         the person running the program. This is so they
  326.         can't open a file that doesn't belong to them! */
  327.  
  328.   s = socket(AF_INET, SOCK_RAW, proto->p_proto);
  329.   if (s<0) errno_crash_and_burn("can't create raw socket");
  330.  
  331.   setuid(getuid());
  332.  
  333.   prog = argv[0];
  334.   ident = getpid() & 0xFFFF;
  335.  
  336.   verbose_flag=1;
  337.  
  338.   opterr=0;
  339.  
  340.   while ((c = getopt(argc,argv,"edhqusavt:i:f:r:")) != EOF) 
  341.      switch (c) {
  342.        case 't': if ( (timeout=atoi(optarg)) <0) usage();  break;
  343.        case 'f': filename= optarg;                         break;
  344.        case 'r': if ((retry=atoi(optarg))<0) usage();      break;
  345.        case 'i': if ((interval=atoi(optarg))<0) usage();   break;
  346.        case 'h': usage();                                  break;
  347.        case 'q': verbose_flag = 0;                           break;
  348.        case 'e': elapsed_flag = 1;                           break;
  349.        case 'd': dns_flag = 1;                             break;
  350.        case 's': stats_flag = 1;                           break;
  351.        case 'u': unreachable_flag = 1;                     break;
  352.        case 'a': alive_flag = 1;                           break;
  353.            case 'v':
  354.                      printf("%s: $Revision: 1.20 $ $Date: 1993/02/23 00:16:38 $\n",argv[0]);
  355.                      printf("%s: comments to schemers@Stanford.EDU\n",argv[0]);
  356.                      exit(0);
  357.            default : fprintf(stderr,"Unknown flag: %s\n",argv[0]); 
  358.                      usage(); break;
  359.      }
  360.  
  361.   if (unreachable_flag && alive_flag) {
  362.     fprintf(stderr,"%s: specify only one of a,u\n",argv[0]);
  363.     usage();
  364.   }
  365.  
  366.   if ( (interval<10 || retry >20 || timeout <250) && getuid()) {
  367.     fprintf(stderr,"%s: these options are too risky for mere mortals.\n",prog);
  368.     fprintf(stderr,"%s: You need i >=10, retry < 20, and t >= 250\n",prog);
  369.     exit(3);
  370.   }
  371.  
  372.   if (alive_flag || unreachable_flag) verbose_flag=0;
  373.  
  374.   argv = &argv[optind];
  375.   if (*argv && filename)   { usage(); }
  376.   if (!*argv && !filename) { filename = "-"; }
  377.  
  378.   if (*argv) while (*argv) {
  379.              add_host(*argv);
  380.              ++argv;
  381.   } else if (filename) {
  382.          FILE *ping_file;
  383.          char line[132];
  384.          char host[132],*p;
  385.          if (strcmp(filename,"-")==0) {
  386.              ping_file=fdopen(0,"r");
  387.          } else {
  388.              ping_file=fopen(filename,"r");
  389.          }
  390.          if (!ping_file) errno_crash_and_burn("fopen");
  391.          while(fgets(line,132,ping_file)) {
  392.            sscanf(line,"%s",host);
  393.               if ((!*host) || (host[0]=='#'))  /* magic to avoid comments */
  394.                 continue;
  395.            p=(char*)malloc(strlen(host)+1);
  396.            if (!p) crash_and_burn("can't malloc host");
  397.            strcpy(p,host);
  398.            add_host(p);
  399.          }
  400.          fclose(ping_file);
  401.   } else usage();
  402.  
  403.   if (!num_hosts) exit(2);
  404.  
  405.   /* allocate array to hold outstanding ping requests */
  406.  
  407.   table = (HOST_ENTRY **) malloc(sizeof(HOST_ENTRY *)*num_hosts);
  408.   if (!table) crash_and_burn("Can't malloc array of hosts");
  409.  
  410.   cursor=rrlist;
  411.  
  412.   for( num_waiting=0; num_waiting < num_hosts; num_waiting++ ) {
  413.       table[num_waiting]=cursor;
  414.       cursor->i = num_waiting;
  415.       cursor=cursor->next;
  416.   }
  417.  
  418.   gettimeofday(&start_time,&tz);
  419.   cursor=rrlist;
  420.   while (num_waiting) {  /* while pings are outstanding */
  421.         if ( (timeval_diff(¤t_time,&cursor->last_time)> timeout) ||
  422.                                                 cursor->num_packets_sent==0)  {
  423.            if (cursor->num_packets_sent>0)  num_timeout++;
  424.             if (cursor->num_packets_sent == retry+1) {
  425.                         if(verbose_flag || unreachable_flag) {
  426.                               if (dns_flag) printf("%s",
  427.                                  get_host_by_address(cursor->saddr.sin_addr));
  428.                               else    printf("%s",cursor->host);
  429.                               if (verbose_flag) printf(" is unreachable");
  430.                               printf("\n");
  431.                        }
  432.                        num_unreachable++;
  433.                        remove_job(cursor); 
  434.            } else send_ping(s,cursor);
  435.      }
  436.       while(wait_for_reply() && num_waiting) {  /* call wfr until we timeout */
  437.                     /* wait! */
  438.       }
  439.       gettimeofday(¤t_time,&tz);
  440.       if (cursor) cursor = cursor->next;
  441.   }  
  442.  
  443.   gettimeofday(&end_time,&tz);
  444.  
  445.   if (stats_flag) {
  446.      fflush(stdout);
  447.      fprintf(stderr,"\n");
  448.      fprintf(stderr," %8d hosts\n",num_hosts);
  449.      fprintf(stderr," %8d alive\n",num_alive);
  450.      fprintf(stderr," %8d unreachable\n",num_unreachable);
  451.      fprintf(stderr," %8d unknown addresses\n",num_noaddress);
  452.      fprintf(stderr,"\n");
  453.      fprintf(stderr," %8d timeouts (waiting for response)\n",num_timeout);
  454.      fprintf(stderr," %8d pings sent\n",num_pingsent);
  455.      fprintf(stderr," %8d pings received\n",num_pingreceived);
  456.      fprintf(stderr,"\n");
  457.  
  458. if (total_replies==0) {
  459.           min_reply=0; max_reply=0; total_replies=1; sum_replies=0;
  460. }
  461.  
  462.      fprintf(stderr," %8d msec (min round trip time)\n",min_reply);
  463.      fprintf(stderr," %8d msec (avg round trip time)\n",(int)sum_replies/total_replies);
  464.      fprintf(stderr," %8d msec (max round trip time)\n",max_reply);
  465.      fprintf(stderr," %8.3f sec (elapsed real time)\n",
  466.          timeval_diff( &end_time,&start_time)/1000.0);
  467.      fprintf(stderr,"\n");
  468.  
  469.   }
  470.  
  471.   if (num_noaddress) exit(2);
  472.   else if (num_alive != num_hosts) exit(1); 
  473.   
  474.   exit(0);
  475.  
  476. }
  477.  
  478.  
  479. /*
  480.  * 
  481.  * Compose and transmit an ICMP_ECHO REQUEST packet.  The IP packet
  482.  * will be added on by the kernel.  The ID field is our UNIX process ID,
  483.  * and the sequence number is an index into an array of outstanding
  484.  * ping requests. The sequence number will later be used to quickly
  485.  * figure out who the ping reply came from.
  486.  *
  487.  */
  488.  
  489. #ifdef _NO_PROTO
  490. void send_ping(s,h)
  491. int s; HOST_ENTRY *h;
  492. #else
  493. void send_ping(int s,HOST_ENTRY *h)
  494. #endif
  495. {
  496.   static char buffer[32];
  497.   struct icmp *icp = (struct icmp *) buffer;
  498.   int n,len;
  499.  
  500.   gettimeofday(&h->last_time,&tz);
  501.  
  502.   icp->icmp_type = ICMP_ECHO;
  503.   icp->icmp_code = 0;
  504.   icp->icmp_cksum = 0;
  505.   icp->icmp_seq = h->i;
  506.   icp->icmp_id = ident;
  507. #define SIZE_ICMP_HDR 8
  508. #define SIZE_PACK_SENT (sizeof(h->num_packets_sent))
  509. #define SIZE_LAST_TIME (sizeof(h->last_time))
  510.  
  511.   bcopy(&h->last_time,&buffer[SIZE_ICMP_HDR],SIZE_LAST_TIME);
  512.   bcopy(&h->num_packets_sent,
  513.              &buffer[SIZE_ICMP_HDR+SIZE_LAST_TIME], SIZE_PACK_SENT);
  514.  
  515.   len = SIZE_ICMP_HDR+SIZE_LAST_TIME+SIZE_PACK_SENT;
  516.  
  517.   icp->icmp_cksum = in_cksum( (u_short *)icp, len );
  518.  
  519.   n = sendto( s, buffer, len, 0, (struct sockaddr *)&h->saddr, 
  520.                                                sizeof(struct sockaddr_in) );
  521.   if( n < 0 || n != len ) {
  522.       if (verbose_flag || unreachable_flag) {
  523.         if (dns_flag) printf("%s",get_host_by_address(h->saddr.sin_addr));
  524.          else printf("%s",cursor->host);
  525.          if (verbose_flag) printf(" error while sending ping: %s\n",
  526.                                sys_errlist[errno]);
  527.          printf("\n");
  528.       }
  529.       num_unreachable++;
  530.       remove_job(h); 
  531.   } else {
  532.        h->num_packets_sent++;
  533.        num_pingsent++;
  534.   }
  535.  
  536. }
  537.  
  538. #ifdef _NO_PROTO
  539. int wait_for_reply()
  540. #else
  541. int wait_for_reply()
  542. #endif
  543. {
  544. int result;
  545. static char buffer[4096];
  546. struct sockaddr_in response_addr;
  547. struct ip *ip;
  548. int hlen;
  549. struct icmp *icp;
  550. int n;
  551. HOST_ENTRY *h;
  552.  
  553. long this_reply;
  554. int the_index;
  555. struct timeval sent_time;
  556.  
  557.  
  558.  result=recvfrom_wto(s,buffer,4096,
  559.                      (struct sockaddr *)&response_addr,interval);
  560.  
  561.   if (result<0) { return 0; } /* timeout */
  562.   
  563.   ip = (struct ip *) buffer;
  564.   hlen = ip->ip_hl << 2;
  565.   if (result < hlen+ICMP_MINLEN) { return(1); /* too short */ }
  566.  
  567.   icp = (struct icmp *)(buffer + hlen);
  568.  
  569.   if ( 
  570.        ( icp->icmp_type != ICMP_ECHOREPLY ) ||   
  571.        ( icp->icmp_id   != ident          ) 
  572.   ) {
  573.        return 1; /* packet received, but not the one we are looking for! */
  574.   }
  575.  
  576.       num_pingreceived++;
  577.  
  578.   if ( ( icp->icmp_seq  >= num_hosts    ) ||
  579.        ( !table[icp->icmp_seq]          ) ||
  580.        ( table[icp->icmp_seq]->saddr.sin_addr.s_addr 
  581.                                 != response_addr.sin_addr.s_addr)) { 
  582.        return 1; /* packet received, don't about it anymore */
  583.   }
  584.  
  585.     n=icp->icmp_seq;
  586.     h=table[n];
  587.  
  588.     gettimeofday(¤t_time,&tz);
  589.     bcopy(&icp->icmp_data[0],&sent_time,sizeof(sent_time));
  590.     bcopy(&icp->icmp_data[SIZE_LAST_TIME],&the_index,  sizeof(the_index));
  591.     this_reply = timeval_diff(¤t_time,&sent_time);
  592.     if (this_reply>max_reply) max_reply=this_reply;
  593.     if (this_reply<min_reply) min_reply=this_reply;
  594.     sum_replies += this_reply;
  595.     total_replies++;
  596.  
  597.     if(verbose_flag||alive_flag) {
  598.        if (dns_flag) printf("%s",get_host_by_address(response_addr.sin_addr));
  599.        else printf("%s",h->host);
  600.        if (verbose_flag) printf(" is alive");
  601.        if (elapsed_flag) printf(" (%d msec)",this_reply);
  602.        printf("\n");
  603.     }
  604.     num_alive++;
  605.     remove_job(h); /* remove job */
  606.     return num_waiting;
  607. }
  608.  
  609. /*
  610.  * Checksum routine for Internet Protocol family headers (C Version)
  611.  * From ping examples in W.Richard Stevens "UNIX NETWORK PROGRAMMING" book.
  612.  */
  613.  
  614. #ifdef _NO_PROTO
  615. int in_cksum(p,n)
  616. u_short *p; int n;
  617. #else
  618. int in_cksum(u_short *p, int n)
  619. #endif
  620. {
  621.   register u_short answer;
  622.   register long sum = 0;
  623.   u_short odd_byte = 0;
  624.  
  625.   while( n > 1 )  { sum += *p++; n -= 2; }
  626.  
  627.   /* mop up an odd byte, if necessary */
  628.   if( n == 1 ) {
  629.       *(u_char *)(&odd_byte) = *(u_char *)p;
  630.       sum += odd_byte;
  631.   }
  632.  
  633.   sum = (sum >> 16) + (sum & 0xffff);    /* add hi 16 to low 16 */
  634.   sum += (sum >> 16);            /* add carry */
  635.   answer = ~sum;            /* ones-complement, truncate*/
  636.   return (answer);
  637. }
  638.  
  639.  
  640. /* add host to linked list of hosts to be pinged */
  641. /* assume memory for *host is ours!!!            */
  642.  
  643. #ifdef _NO_PROTO
  644. void add_host(host)
  645. char *host;
  646. #else
  647. void add_host(char *host)
  648. #endif
  649. {
  650.   HOST_ENTRY *p;
  651.   struct hostent *host_ent;
  652.   struct in_addr *host_add;
  653.  
  654. #ifndef __alpha
  655.   u_long ipaddress = inet_addr(host);
  656. #else
  657.   u_int ipaddress = inet_addr(host);
  658. #endif
  659.  
  660.   if ( (ipaddress == -1) &&
  661.        ( ((host_ent=gethostbyname(host)) == 0) ||
  662.           ((host_add = (struct in_addr *) *(host_ent->h_addr_list))==0))
  663.      )  {
  664.           if (verbose_flag) fprintf(stderr,"%s address not found\n",host);
  665.           num_noaddress++;
  666.           return;
  667.        }
  668.  
  669.   p = (HOST_ENTRY *) malloc(sizeof(HOST_ENTRY));
  670.   if (!p) crash_and_burn("can't allocate HOST_ENTRY");
  671.  
  672.   p->host=host;
  673.   p->num_packets_sent = 0;
  674.   p->last_time.tv_sec =0;
  675.   p->last_time.tv_usec =0;
  676.  
  677.   bzero((char*) &p->saddr, sizeof(p->saddr));
  678.   p->saddr.sin_family      = AF_INET;
  679.  
  680.   if (ipaddress==-1) p->saddr.sin_addr = *host_add; 
  681.   else p->saddr.sin_addr.s_addr = ipaddress;
  682.  
  683.   if (!rrlist) {
  684.       rrlist = p;
  685.       p->next = p;
  686.       p->prev = p;
  687.   } else {
  688.       p->next = rrlist;
  689.       p->prev = rrlist->prev;
  690.       p->prev->next = p;
  691.       p->next->prev = p;
  692.       rrlist = p;
  693.   }
  694.   num_hosts++;
  695. }
  696.  
  697. #ifdef _NO_PROTO
  698. void remove_job(h)
  699. HOST_ENTRY *h;
  700. #else
  701. void remove_job(HOST_ENTRY *h)
  702. #endif
  703. {
  704.  
  705.   table[h->i]=NULL;
  706.   --num_waiting;
  707.  
  708.   if (num_waiting) {                    /* remove us from list of jobs */
  709.        h->prev->next = h->next;
  710.        h->next->prev = h->prev;
  711.        if (h==cursor) { cursor = h-> next; }
  712.   } else {     
  713.        cursor=NULL;
  714.        rrlist=NULL;
  715.   }
  716.  
  717. }
  718.  
  719. #ifdef _NO_PROTO
  720. char *get_host_by_address(in)
  721. struct in_addr in;
  722. #else
  723. char *get_host_by_address(struct in_addr in)
  724. #endif
  725. {
  726.   struct hostent *h;
  727.    h=gethostbyaddr((char *) &in,sizeof(struct in_addr),AF_INET);
  728.    if (h==NULL || h->h_name==NULL) return inet_ntoa(in);
  729.    else return h->h_name;
  730. }
  731.  
  732.  
  733. #ifdef _NO_PROTO
  734. void crash_and_burn(message)
  735. char *message;
  736. #else
  737. void crash_and_burn(char *message)
  738. #endif
  739. {
  740.   if (verbose_flag) fprintf(stderr,"%s: %s\n",prog,message);
  741.   exit(4);
  742. }
  743.  
  744. #ifdef _NO_PROTO
  745. void errno_crash_and_burn(message)
  746. char *message;
  747. #else
  748. void errno_crash_and_burn(char *message)
  749. #endif
  750. {
  751.   if (verbose_flag)
  752.         fprintf(stderr,"%s: %s : %s\n",prog,message,sys_errlist[errno]);
  753.   exit(4);
  754. }
  755.  
  756. #ifdef _NO_PROTO
  757. long timeval_diff(a,b)
  758. struct timeval *a,*b;
  759. #else
  760. long timeval_diff(struct timeval *a,struct timeval *b)
  761. #endif
  762. {
  763. double temp;
  764.  
  765. temp = 
  766.   (((a->tv_sec*1000000)+ a->tv_usec) - 
  767.      ((b->tv_sec*1000000)+ b->tv_usec))/1000;
  768.  
  769. return (long) temp;
  770.  
  771. }
  772.  
  773. /*
  774.  * recvfrom_wto: receive with timeout
  775.  *      returns length of data read or -1 if timeout
  776.  *      crash_and_burn on any other errrors
  777.  *
  778.  */
  779.  
  780.  
  781. #ifdef _NO_PROTO
  782. int recvfrom_wto (s,buf,len, saddr, timo)
  783. int s; char *buf; int len; struct sockaddr *saddr; int timo;
  784. #else
  785. int recvfrom_wto (int s, char *buf, int len, struct sockaddr *saddr, int timo)
  786. #endif
  787. {
  788.   int nfound,slen,n;
  789.   struct timeval to;
  790.   fd_set readset,writeset;
  791.  
  792.   to.tv_sec  = timo/1000;
  793.   to.tv_usec = (timo - (to.tv_sec*1000))*1000;
  794.  
  795.   FD_ZERO(&readset);
  796.   FD_ZERO(&writeset);
  797.   FD_SET(s,&readset);
  798.   nfound = select(s+1,&readset,&writeset,NULL,&to);
  799.   if (nfound<0) errno_crash_and_burn("select");
  800.   if (nfound==0) return -1;  /* timeout */
  801.   slen=sizeof(struct sockaddr);
  802.   n=recvfrom(s,buf,len,0,saddr,&slen);
  803.   if (n<0) errno_crash_and_burn("recvfrom");
  804.   return n;
  805. }
  806.  
  807. #ifdef _NO_PROTO
  808. void usage()
  809. #else
  810. void usage()
  811. #endif
  812. {
  813.   fprintf(stderr,"\n");
  814.   fprintf(stderr,"Usage: %s [options] [systems...]\n",prog);
  815.   fprintf(stderr,"   -a         show systems that are alive\n");
  816.   fprintf(stderr,"   -d         use dns to lookup address for return ping packet\n");
  817.   fprintf(stderr,"   -e         show elapsed time on return packets\n");
  818.   fprintf(stderr,"   -f file    read list of systems from a file ( - means stdin)\n");
  819.   fprintf(stderr,"   -i n       interval (between ping packets) in milliseconds (default %d)\n",interval);
  820.   fprintf(stderr,"   -q         quiet (don't show per host results)\n");
  821.   fprintf(stderr,"   -r n       retry limit (default %d)\n",retry);
  822.   fprintf(stderr,"   -s         dump final stats\n");
  823.   fprintf(stderr,"   -t n       individual host timeout in milliseconds (default %d)\n",timeout);
  824.   fprintf(stderr,"   -u         show systems that are unreachable\n");
  825.   fprintf(stderr,"   -v         show version\n");
  826.   fprintf(stderr,"   systems    list of systems to check (if no -f specified)\n");
  827.   fprintf(stderr,"\n");
  828.   exit(3);
  829. }
  830.